/***************************************************************************
 * file:        BaseNetwLayer_STRT.cc
 *
 * author:      Daniel Willkomm
 *
 * copyright:   (C) 2004 Telecommunication Networks Group (TKN) at
 *              Technische Universitaet Berlin, Germany.
 *
 *              This program is free software; you can redistribute it
 *              and/or modify it under the terms of the GNU General Public
 *              License as published by the Free Software Foundation; either
 *              version 2 of the License, or (at your option) any later
 *              version.
 *              For further information see file COPYING
 *              in the top level directory
 ***************************************************************************
 * part of:     framework implementation developed by tkn
 * description: network layer: general class for the network layer
 *              subclass to create your own network layer
 ***************************************************************************/


#include "BaseNetwLayer_STRT.h"
#include "NetwControlInfo.h"
#include "NetwToMacControlInfo.h"
#include "BaseMacLayer.h"
#include "AddressingInterface.h"

#include <cassert>

Define_Module(BaseNetwLayer_STRT);

std::vector<int> BaseNetwLayer_STRT::addressVector(4,-99);

void BaseNetwLayer_STRT::initialize(int stage)
{
	BaseLayer::initialize(stage);

	if(stage==0){
		coreDebug = par("coreDebug").boolValue();
		headerLength= par("headerLength");
		arp = FindModule<ArpInterface*>::findSubModule(findHost());
		ipHst = par("ipHst").longValue();
		numHosts = 4; //par("numHosts") ? par("numHosts").longValue() : 4;
	}
	else if(stage == 1) {
		// see if there is an addressing module available
		// otherwise use module id as network address
		AddressingInterface* addrScheme = FindModule<AddressingInterface*>
		::findSubModule(findHost());
		if(addrScheme)
		{
			myNetwAddr = addrScheme->myNetwAddr(this);
		} else {
			myNetwAddr = getId();
		}
		addressVector[ipHst] = myNetwAddr;
		coreEV << "ipHst " << ipHst << " myNetwAddr " << myNetwAddr << " addressVector ";
		for (std::vector<int>::const_iterator it = addressVector.begin(); it != addressVector.end(); it++) {
			coreEV << *it << " ";
		}
		coreEV << endl;

		for (int i = 0; i != numHosts; i++) {
			forwardingTable[i] = -99;
			destTable[i] = -99;
		}

		if (ipHst == 0) {
			forwardingTable[1] = 1;
			forwardingTable[2] = 1;

			destTable[1] = 1;
			destTable[2] = 2;
		}

		if (ipHst == 1) {
			forwardingTable[0] = 0;
			forwardingTable[2] = 2;
			forwardingTable[3] = 2;

			destTable[0] = 0;
			destTable[2] = 2;
			destTable[3] = 3;
		}

		if (ipHst == 2) {
			forwardingTable[0] = 1;
			forwardingTable[1] = 1;
			forwardingTable[3] = 3;

			destTable[0] = 0;
			destTable[1] = 1;
			destTable[3] = 3;
		}

		if (ipHst == 3) {
			forwardingTable[1] = 2;
			forwardingTable[2] = 2;

			destTable[1] = 1;
			destTable[2] = 2;
		}

	}
}


/**
 * Decapsulates the packet from the received Network packet
 **/
cMessage* BaseNetwLayer_STRT::decapsMsg(NetwPkt *msg)
{
	cMessage *m = msg->decapsulate();
	m->setControlInfo(new NetwControlInfo(msg->getSrcAddr()));
	// delete the netw packet
	delete msg;
	return m;
}


/**
 * Encapsulates the received ApplPkt into a NetwPkt and set all needed
 * header fields.
 **/
NetwPkt* BaseNetwLayer_STRT::encapsMsg(cPacket *appPkt) {
	int macAddr;
	int netwAddr;

	coreEV <<"in encaps...\n";

	NetwPkt *pkt = new NetwPkt(appPkt->getName(), appPkt->getKind());
	pkt->setBitLength(headerLength);

	NetwControlInfo* cInfo = dynamic_cast<NetwControlInfo*>(appPkt->removeControlInfo());

	if(cInfo == 0){
		EV << "warning: Application layer did not specifiy a destination L3 address\n"
				<< "\tusing broadcast address instead\n";
		netwAddr = L3BROADCAST;
	} else {
		coreEV <<"CInfo removed, netw addr="<< cInfo->getNetwAddr()<<endl;
		netwAddr = cInfo->getNetwAddr();
		delete cInfo;
	}

	//
	// re-routing
	// if netwAddr > -1 ; do not re-rout to a different final destination address . this is a reply
	//

	pkt->setSrcAddr(myNetwAddr);
	pkt->setDestAddr(netwAddr);
	coreEV << " netw "<< myNetwAddr << " sending packet" <<endl;
	if(netwAddr == L3BROADCAST) {
		coreEV << "sendDown: nHop=L3BROADCAST -> message has to be broadcasted"
				<< " -> set destMac=L2BROADCAST\n";
		macAddr = L2BROADCAST;
	}
	else{
		coreEV <<"sendDown: get the MAC address\n";
		macAddr = arp->getMacAddr(netwAddr);
	}

	pkt->setControlInfo(new NetwToMacControlInfo(macAddr));

	//encapsulate the application packet
	pkt->encapsulate(appPkt);
	coreEV <<" pkt encapsulated\n";
	return pkt;
}

/**
 * Redefine this function if you want to process messages from lower
 * layers before they are forwarded to upper layers
 *
 *
 * If you want to forward the message to upper layers please use
 * @ref sendUp which will take care of decapsulation and thelike
 **/
void BaseNetwLayer_STRT::handleLowerMsg(cMessage* msg)
{
	NetwPkt *m = static_cast<NetwPkt *>(msg);
	coreEV << " handling packet from " << m->getSrcAddr() << endl;
	sendUp(decapsMsg(m));
}

/**
 * Redefine this function if you want to process messages from upper
 * layers before they are send to lower layers.
 *
 * For the BaseNetwLayer_STRT we just use the destAddr of the network
 * message as a nextHop
 *
 * To forward the message to lower layers after processing it please
 * use @ref sendDown. It will take care of anything needed
 **/
void BaseNetwLayer_STRT::handleUpperMsg(cMessage* msg)
{
	assert(dynamic_cast<cPacket*>(msg));
	sendDown(encapsMsg(static_cast<cPacket*>(msg)));
}

/**
 * Redefine this function if you want to process control messages
 * from lower layers.
 *
 * This function currently handles one messagetype: TRANSMISSION_OVER.
 * If such a message is received in the network layer it is deleted.
 * This is done as this type of messages is passed on by the BaseMacLayer.
 *
 * It may be used by network protocols to determine when the lower layers
 * are finished sending a message.
 **/
void BaseNetwLayer_STRT::handleLowerControl(cMessage* msg)
{
	switch (msg->getKind())
	{
	case BaseMacLayer::TX_OVER:
		delete msg;
		break;
	default:
		EV << "BaseNetwLayer_STRT does not handle control messages called "
		<< msg->getName() << endl;
		delete msg;
	}
}
